package businessObject;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import businessObject.GestionUsuario;

import data.IUsuarioDAO;
import data.JDBCUsuarioDAO;
import dataTransferObject.*;
import estrategiasRecomendadorAmistad.*;;


public class RecomendarAmigos {

	private EstrategiaAficionesEnComun eaf;
	private EstrategiaAmigosEnComun eac;
	private EstrategiaLugaresDeInteresEnComun eli;
	private EstrategiaZonaYDistanciaUsuarios ezd;
	private EstrategiaSexoUsuarios esx;
	private EstrategiaEdadUsuarios eed;
	private EstrategiaEdadMascotas eem;
	private EstrategiaSexoMascotas esm;
	private EstrategiaRazaMascotas erm;
	
	private static RecomendarAmigos recomendador = null;
	private static Properties dbprops = new Properties();

	
	public static synchronized RecomendarAmigos getInstance() {
		if (recomendador == null) {
			recomendador = new RecomendarAmigos();
		}
		return recomendador;
	}

	private RecomendarAmigos() {
		 eaf = new EstrategiaAficionesEnComunConPrioridadMedia();
		 eac = new EstrategiaAmigosEnComunConPrioridadMedia();
		 eli = new EstrategiaLugaresDeInteresEnComunConPrioridadMedia();
		 ezd = new EstrategiaZonaYDistanciaUsuariosConPrioridadMedia();
		 esx = new EstrategiaSexoUsuariosIndiferente();
		 eed = new EstrategiaEdadUsuariosConPrioridadMedia();
		 eem = new EstrategiaEdadMascotasConPrioridadMedia();
		 esm = new EstrategiaSexoMascotasIndiferente();
		 erm = new EstrategiaRazaMascotasConPrioridadMedia();

	      try {
	    	  InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("estrategiasRecomendador.properties"); 
	    	  dbprops.load(is);
		} catch (Exception e1) {
			System.err.println("El fichero de propiedades de las estrategias no se ha encontrado");
			e1.printStackTrace();
		}
	}
	
	public List<Usuario> sugerenciasDeAmistad(Usuario usuario, Integer mostrarResultados,List<String> preferencias) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
		if(mostrarResultados == null)
			mostrarResultados = 3;
	
		List<Usuario> sugerenciasResultado = new ArrayList<Usuario>();
		
		SortedMap<Double,Usuario> sugerenciasConPuntos = calcularCompatibilidadEntreUsuarios(usuario,preferencias);
		
		List<Usuario> sugerenciasTotales = new ArrayList<Usuario>(sugerenciasConPuntos.values());
		
		Collections.reverse(sugerenciasTotales);
		
		if(mostrarResultados > sugerenciasTotales.size())
			mostrarResultados = sugerenciasTotales.size();
		
		for(int i = 0;i<mostrarResultados;i++){
			sugerenciasResultado.add(sugerenciasTotales.get(i));
		}		
		
		return sugerenciasResultado;
		
	}
	
	public SortedMap<Double,Usuario> calcularCompatibilidadEntreUsuarios(Usuario usuario,List<String> preferencias) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
		// TODO Auto-generated method stub
		Double puntos = 0.0;
		SortedMap<Double,Usuario> sugerencias = new TreeMap<Double, Usuario>();

		List<Usuario> amigosDeamigos = getAmigosDeAmigos(usuario);
		
		for(Usuario posibleAmigo:amigosDeamigos){
			puntos = calculaAfinidadMedianteEstrategia(usuario, posibleAmigo,preferencias);
			System.out.println("El posible amigo "+posibleAmigo.getEmail()+" tiene "+puntos+" puntos.");
			sugerencias.put(puntos, posibleAmigo);
			puntos = 0.0;
		}
		
		return sugerencias;
	}
	
	public Double calculaAfinidadMedianteEstrategia(Usuario usuario, Usuario posibleAmigo,List<String> preferencias) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
		Double puntos = 0.0;
		
		if(!preferencias.isEmpty()){
			eaf = (EstrategiaAficionesEnComun) Class.forName(dbprops.getProperty(preferencias.get(0))).newInstance();
			eac = (EstrategiaAmigosEnComun) Class.forName(dbprops.getProperty(preferencias.get(1))).newInstance();
			eli = (EstrategiaLugaresDeInteresEnComun) Class.forName(dbprops.getProperty(preferencias.get(2))).newInstance();
			esx = (EstrategiaSexoUsuarios) Class.forName(dbprops.getProperty(preferencias.get(3))).newInstance();
			eed = (EstrategiaEdadUsuarios) Class.forName(dbprops.getProperty(preferencias.get(4))).newInstance();
			ezd = (EstrategiaZonaYDistanciaUsuarios) Class.forName(dbprops.getProperty(preferencias.get(5))).newInstance();
			erm = (EstrategiaRazaMascotas) Class.forName(dbprops.getProperty(preferencias.get(6))).newInstance();
			esm = (EstrategiaSexoMascotas) Class.forName(dbprops.getProperty(preferencias.get(7))).newInstance();
			eem = (EstrategiaEdadMascotas) Class.forName(dbprops.getProperty(preferencias.get(8))).newInstance();
		
		}
		
		puntos += eaf.calcularAfinidad(usuario, posibleAmigo);
		puntos += eac.calcularAfinidad(usuario, posibleAmigo);
		puntos += eli.calcularAfinidad(usuario, posibleAmigo);
		puntos += ezd.calcularAfinidad(usuario, posibleAmigo);
		puntos += esx.calcularAfinidad(usuario, posibleAmigo);
		puntos += eed.calcularAfinidad(usuario, posibleAmigo);
		puntos += eem.calcularAfinidad(usuario, posibleAmigo);
		puntos += esm.calcularAfinidad(usuario, posibleAmigo);
		puntos += erm.calcularAfinidad(usuario, posibleAmigo);
		
		return puntos;
		
	}
	
	public List<Usuario> getAmigosDeAmigos(Usuario usuario){
		IUsuarioDAO usuarioDAO= new JDBCUsuarioDAO();
		Set<Usuario> amigosDeAmigos = new HashSet<Usuario>();

		for(Usuario amigo : usuario.getAmigos()){
			usuarioDAO.actualizaAmigos(amigo);
			amigosDeAmigos.addAll(amigo.getAmigos());
		}
		amigosDeAmigos.removeAll(usuario.getAmigos());
		
		for(Usuario amigoDeAmigo : amigosDeAmigos){
			usuarioDAO.actualizaAmigos(amigoDeAmigo);
		}
		
		if(amigosDeAmigos.contains(usuario)){
			amigosDeAmigos.remove(usuario);
		}
		
		return new ArrayList<Usuario>(amigosDeAmigos);
		
	}
	
	public boolean anyadirNuevoAmigo(Usuario amigo, Usuario usuario){
		IUsuarioDAO usuarioDAO = new JDBCUsuarioDAO();
		boolean anyadido = usuarioDAO.insertNuevoAmigo(amigo, usuario);
		return anyadido;
	}
	
	
	public boolean eliminarAmigo(Usuario amigo, Usuario usuario){
		IUsuarioDAO usuarioDAO = new JDBCUsuarioDAO();
		boolean eliminado = usuarioDAO.deleteAmigo(amigo, usuario);
		return eliminado;
	}


}
